
<!doctype html>
<html lang="en" class="no-js">
  <head>
    
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      
        <meta name="description" content="SmartEditor 文档">
      
      
        <meta name="author" content="chainmaker">
      
      
        <link rel="canonical" href="http://ide.chainmaker.org.cn/doc/SmartEditor%20%E6%80%8E%E4%B9%88%E5%86%99%E5%90%88%E7%BA%A6/">
      
      
        <link rel="prev" href="../SmartEditor%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E/">
      
      
      <link rel="icon" href="../images/favicon.png">
      <meta name="generator" content="mkdocs-1.4.3, mkdocs-material-9.1.20">
    
    
      
        <title>SmartEditor 怎么写合约 - SmartEditor 文档</title>
      
    
    
      <link rel="stylesheet" href="../assets/stylesheets/main.eebd395e.min.css">
      
      

    
    
    
      
    
    
    <script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
    
      

    
    
    
  </head>
  
  
    <body dir="ltr">
  
    
    
      <script>var palette=__md_get("__palette");if(palette&&"object"==typeof palette.color)for(var key of Object.keys(palette.color))document.body.setAttribute("data-md-color-"+key,palette.color[key])</script>
    
    <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
    <input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
    <label class="md-overlay" for="__drawer"></label>
    <div data-md-component="skip">
      
        
        <a href="#ide" class="md-skip">
          Skip to content
        </a>
      
    </div>
    <div data-md-component="announce">
      
    </div>
    
    
      

  

<header class="md-header md-header--shadow" data-md-component="header">
  <nav class="md-header__inner md-grid" aria-label="Header">
    <a href=".." title="SmartEditor 文档" class="md-header__button md-logo" aria-label="SmartEditor 文档" data-md-component="logo">
      
  <img src="../images/favicon.png" alt="logo">

    </a>
    <label class="md-header__button md-icon" for="__drawer">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
    </label>
    <div class="md-header__title" data-md-component="header-title">
      <div class="md-header__ellipsis">
        <div class="md-header__topic">
          <span class="md-ellipsis">
            SmartEditor 文档
          </span>
        </div>
        <div class="md-header__topic" data-md-component="header-topic">
          <span class="md-ellipsis">
            
              SmartEditor 怎么写合约
            
          </span>
        </div>
      </div>
    </div>
    
    
    
      <label class="md-header__button md-icon" for="__search">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
      </label>
      <div class="md-search" data-md-component="search" role="dialog">
  <label class="md-search__overlay" for="__search"></label>
  <div class="md-search__inner" role="search">
    <form class="md-search__form" name="search">
      <input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
      <label class="md-search__icon md-icon" for="__search">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
      </label>
      <nav class="md-search__options" aria-label="Search">
        
        <button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
        </button>
      </nav>
      
    </form>
    <div class="md-search__output">
      <div class="md-search__scrollwrap" data-md-scrollfix>
        <div class="md-search-result" data-md-component="search-result">
          <div class="md-search-result__meta">
            Initializing search
          </div>
          <ol class="md-search-result__list" role="presentation"></ol>
        </div>
      </div>
    </div>
  </div>
</div>
    
    
  </nav>
  
</header>
    
    <div class="md-container" data-md-component="container">
      
      
        
          
        
      
      <main class="md-main" data-md-component="main">
        <div class="md-main__inner md-grid">
          
            
              
              <div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    


<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
  <label class="md-nav__title" for="__drawer">
    <a href=".." title="SmartEditor 文档" class="md-nav__button md-logo" aria-label="SmartEditor 文档" data-md-component="logo">
      
  <img src="../images/favicon.png" alt="logo">

    </a>
    SmartEditor 文档
  </label>
  
  <ul class="md-nav__list" data-md-scrollfix>
    
      
      
      

  
  
  
    <li class="md-nav__item">
      <a href=".." class="md-nav__link">
        Home
      </a>
    </li>
  

    
      
      
      

  
  
  
    <li class="md-nav__item">
      <a href="../SmartEditor%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E/" class="md-nav__link">
        SmartEditor 使用说明
      </a>
    </li>
  

    
      
      
      

  
  
    
  
  
    <li class="md-nav__item md-nav__item--active">
      
      <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
      
      
      
        <label class="md-nav__link md-nav__link--active" for="__toc">
          SmartEditor 怎么写合约
          <span class="md-nav__icon md-icon"></span>
        </label>
      
      <a href="./" class="md-nav__link md-nav__link--active">
        SmartEditor 怎么写合约
      </a>
      
        

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#ide" class="md-nav__link">
    怎么在IDE中写合约
  </a>
  
    <nav class="md-nav" aria-label="怎么在IDE中写合约">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#ide_1" class="md-nav__link">
    IDE简介
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#sdk" class="md-nav__link">
    SDK 简介
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#sdk_1" class="md-nav__link">
    使用 SDK写一个简单合约
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#sdk_2" class="md-nav__link">
    SDK 详细介绍
  </a>
  
    <nav class="md-nav" aria-label="SDK 详细介绍">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#sdkinterface" class="md-nav__link">
    SDKInterface 接口
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#sdkinterface_1" class="md-nav__link">
    SDKInterface 详细介绍
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
        
          <li class="md-nav__item">
  <a href="#_1" class="md-nav__link">
    编写合约注意事项
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
    </ul>
  
</nav>
      
    </li>
  

    
  </ul>
</nav>
                  </div>
                </div>
              </div>
            
            
              
              <div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#ide" class="md-nav__link">
    怎么在IDE中写合约
  </a>
  
    <nav class="md-nav" aria-label="怎么在IDE中写合约">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#ide_1" class="md-nav__link">
    IDE简介
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#sdk" class="md-nav__link">
    SDK 简介
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#sdk_1" class="md-nav__link">
    使用 SDK写一个简单合约
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#sdk_2" class="md-nav__link">
    SDK 详细介绍
  </a>
  
    <nav class="md-nav" aria-label="SDK 详细介绍">
      <ul class="md-nav__list">
        
          <li class="md-nav__item">
  <a href="#sdkinterface" class="md-nav__link">
    SDKInterface 接口
  </a>
  
</li>
        
          <li class="md-nav__item">
  <a href="#sdkinterface_1" class="md-nav__link">
    SDKInterface 详细介绍
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
        
          <li class="md-nav__item">
  <a href="#_1" class="md-nav__link">
    编写合约注意事项
  </a>
  
</li>
        
      </ul>
    </nav>
  
</li>
      
    </ul>
  
</nav>
                  </div>
                </div>
              </div>
            
          
          
            <div class="md-content" data-md-component="content">
              <article class="md-content__inner md-typeset">
                
                  


  <h1>SmartEditor 怎么写合约</h1>

<h2 id="ide">怎么在IDE中写合约<a class="headerlink" href="#ide" title="Permanent link">#</a></h2>
<h3 id="ide_1">IDE简介<a class="headerlink" href="#ide_1" title="Permanent link">#</a></h3>
<p>合约IDE是一个在线合约编辑器，使用合约IDE可以方便、快速的写合约。我们看一下合约IDE长什么样：</p>
<p><img alt="" src="../images/docs/dashboard.jpg" /></p>
<p><strong>IDE功能介绍</strong>：</p>
<ol>
<li>文件目录：在 <code>workspace</code> 下创建的每一个目录都是一个单独的合约项目。可以创建多个合约项目。</li>
<li>合约调试：模拟执行合约。  <ul>
<li>合约执行过程中打印的日志会在 <code>控制台-&gt;输出</code> 中展示。  </li>
<li>合约执行过程中发送的事件会在<code>控制台-&gt;事件</code> 中展示。  </li>
<li>合约执行的世界状态会在 <code>控制台-&gt;世界状态</code> 中展示。  </li>
<li>合约执行结果会在执行结果下面显示。  </li>
</ul>
</li>
<li>合约编译：编译合约，生成要部署的合约文件。</li>
<li>合约部署：调用插件，通过插件部署合约到链上。</li>
<li>合约调用：调用插件，通过插件调用链上的合约。</li>
<li>代码编辑区：编写合约代码的地方。</li>
<li>用户信息：用户名退出登录。</li>
<li>代码大纲：显示代码整体结构，点击可快速跳转。</li>
<li>控制台-输出：输出合约编译，合约调用过程的日志信息。</li>
<li>控制台-事件：展示模拟执行过程产生的事件。</li>
<li>控制台-世界状态：展示模拟执行时链的世界状态。</li>
<li>帮助文档：点击跳转到帮助页面。</li>
<li>设置：个性化设置。</li>
</ol>
<h3 id="sdk">SDK 简介<a class="headerlink" href="#sdk" title="Permanent link">#</a></h3>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="s">&quot;chainmaker/sandbox&quot;</span>
<span class="w">    </span><span class="s">&quot;chainmaker/sdk&quot;</span>
<span class="w">    </span><span class="s">&quot;chainmaker/pb/protogo&quot;</span>
</code></pre></div>
<p>上面是合约SDK提供的包。我们写合约时不需要完全了解包里面的内容，只需要知道里面一小部内容即可。</p>
<p><code>chainmaker/sandbox</code>：是合约的入口函数。</p>
<p><code>chainmaker/sdk</code>：是合约SDK的核心包. </p>
<p><code>chainmaker/pb/protogo</code>：我们只需要知道里面的一个结构体类型 <code>Response</code>  ，<code>Response</code> 是合约初始化方法和合约调用返回值的类型。</p>
<p>了解上面这些内容我们就可以开始在IDE中写合约了。下面我们看一下怎么写一个合约。</p>
<h3 id="sdk_1">使用 <code>SDK</code>写一个简单合约<a class="headerlink" href="#sdk_1" title="Permanent link">#</a></h3>
<p>下面我们将写一个合约，合约的功能是保存和查询用户的年龄信息，合约的名字叫 <code>age_contract</code>。合约有两个方法：</p>
<p>第一个方法 <code>saveAge</code>：保存年龄信息。接收两个参数：姓名 <code>name</code> 和年龄 <code>age</code>，把姓名和年龄保存到链上，成功返回成功信息，失败返回错误信息。</p>
<p>第二个方法 <code>getAge</code>：查询年龄信息。接收一个参数 <code>name</code> ，如果链上存在用户的年龄信息则返回，如果不存在则返回 <code>-1</code>。</p>
<p><strong>编写合约的步骤如下：</strong></p>
<ol>
<li>
<p>创建合约。在 <code>文件目录的 workspace</code>上点击鼠标右键，选择创建合约工程，输入合约名字 <code>age_contract</code>，然后点击创建，此时在文件目录会有一个合约工程 <code>age_contract</code>。</p>
</li>
<li>
<p>第二步创建合约文件。在 <code>age_contract</code> 上点击鼠标右键，选择创建文件，输入 <code>main.go</code>。然后点击创建，此时在 <code>arg_contract</code> 目录会有一个 <code>main.go</code> 文件。</p>
</li>
<li>
<p>开始编写合约。打开 <code>main.go</code>, 复制下面代码到代码编辑区。保存代码 (<code>CTRL+s</code>)，保存时合约IDE会自动生成 <code>go.mod</code> 和 <code>go.sum</code> 文件。</p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="kn">package</span><span class="w"> </span><span class="nx">main</span>

<span class="w">    </span><span class="kn">import</span><span class="w"> </span><span class="p">(</span>
<span class="w">        </span><span class="s">&quot;chainmaker/pb/protogo&quot;</span>
<span class="w">        </span><span class="s">&quot;chainmaker/sdk&quot;</span>
<span class="w">        </span><span class="s">&quot;chainmaker/sandbox&quot;</span>
<span class="w">    </span><span class="p">)</span>

<span class="w">    </span><span class="c1">// AgeContract save and get age</span>
<span class="w">    </span><span class="kd">type</span><span class="w"> </span><span class="nx">AgeContract</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// InitContract 合约初始化方法，会在合约部署到链上时执行</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InitContract</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Init contract success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// InvokeContract 调用合约，在链上执行合约时，实际调用的是这个方法，此时调用合约会直接返回错误信息 `no contarct method`</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InvokeContract</span><span class="p">(</span><span class="nx">method</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;invalid method&quot;</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// UpgradeContract 合约升级方法, 会在合约升级时候调用 </span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">UpgradeContract</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Upgrade contract success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">//合约入口</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="c1">//运行合约</span>
<span class="w">        </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sandbox</span><span class="p">.</span><span class="nx">Start</span><span class="p">(</span><span class="nb">new</span><span class="p">(</span><span class="nx">AgeContract</span><span class="p">))</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nb">panic</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">    </span><span class="p">}</span>
</code></pre></div>
<p>这段代码是空合约模板，没有实现任何方法，以后写合约的时候都可以先复制这段代码初始化合约文件。后面我们要做的是增加两个合约方法 <code>saveAge</code> 和 <code>getAge</code>。</p>
</li>
<li>
<p>增加 <code>saveAge</code> 和 <code>getAge</code> 方法。复制下面代码到 <code>main.go</code>。</p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="kn">package</span><span class="w"> </span><span class="nx">main</span>

<span class="w">    </span><span class="kn">import</span><span class="w"> </span><span class="p">(</span>
<span class="w">        </span><span class="s">&quot;strconv&quot;</span>

<span class="w">        </span><span class="s">&quot;chainmaker/pb/protogo&quot;</span>
<span class="w">        </span><span class="s">&quot;chainmaker/sdk&quot;</span>
<span class="w">        </span><span class="s">&quot;chainmaker/sandbox&quot;</span>
<span class="w">    </span><span class="p">)</span>

<span class="w">    </span><span class="c1">// AgeContract save and get age</span>
<span class="w">    </span><span class="kd">type</span><span class="w"> </span><span class="nx">AgeContract</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// InitContract 合约初始化方法，会在合约部署到链上时执行</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InitContract</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Init contract success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// InvokeContract 调用合约，在链上执行合约时，实际调用的是这个方法</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InvokeContract</span><span class="p">(</span><span class="nx">method</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;invalid method&quot;</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// UpgradeContract 合约升级方法, 会在合约升级时候调用 </span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">UpgradeContract</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Upgrade contract success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// saveAge 保存用户年龄信息</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">saveAge</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="c1">//获取所有的合约参数</span>
<span class="w">        </span><span class="nx">args</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetArgs</span><span class="p">()</span>

<span class="w">        </span><span class="nx">name</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">])</span>
<span class="w">        </span><span class="nx">ageStr</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="s">&quot;age&quot;</span><span class="p">])</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nx">ageStr</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;name or age is empty&quot;</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">strconv</span><span class="p">.</span><span class="nx">Atoi</span><span class="p">(</span><span class="nx">ageStr</span><span class="p">)</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;convert age to int fail. err: &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">()</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">        </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="c1">//保存用户年龄信息到链</span>
<span class="w">        </span><span class="nx">err</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">PutStateFromKey</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span><span class="w"> </span><span class="nx">ageStr</span><span class="p">)</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;put state from key fail. err: &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">()</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="c1">//返回合约执行成功信息</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// getAge 获取用户年龄信息</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">getAge</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="c1">//获取所有的合约参数</span>
<span class="w">        </span><span class="nx">args</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetArgs</span><span class="p">()</span>

<span class="w">        </span><span class="nx">name</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">])</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;name is empty&quot;</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;-1&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="nx">ageStr</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetStateFromKey</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;get state from key fail. err: &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">()</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;-1&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">ageStr</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;age not found&quot;</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;-1&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="c1">//返回用户年龄</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="nx">ageStr</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="c1">//运行合约</span>
<span class="w">        </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sandbox</span><span class="p">.</span><span class="nx">Start</span><span class="p">(</span><span class="nb">new</span><span class="p">(</span><span class="nx">AgeContract</span><span class="p">))</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nb">panic</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">    </span><span class="p">}</span>
</code></pre></div>
<p>这段代码较第三步增加了两个方法：</p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">saveAge</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{}</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">getAge</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{}</span>
</code></pre></div>
<p>这两个方法分别是存储和查询用户年龄。</p>
<p>此时<code>saveAge</code> 和  <code>getAge</code> 方法是孤立存在的，不能通过合约调用到对应的方法，下面我们将在合约调用方法中关联合约和方法，这样调用合约方法时就能找到对应的方法。</p>
</li>
<li>
<p>关联合约方法。复制完整的合约代码到 <code>main.go</code>。</p>
<p>修改 <code>AgeContract .InvokeContract()</code> 方法，增加关联合约方法代码。修改后的内容如下：</p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="c1">// InvokeContract 调用合约，在链上执行合约时，实际调用的是这个方法</span>

<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InvokeContract</span><span class="p">(</span><span class="nx">method</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>

<span class="w">        </span><span class="k">switch</span><span class="w"> </span><span class="nx">method</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;saveAge&quot;</span><span class="p">:</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">saveAge</span><span class="p">()</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;getAge&quot;</span><span class="p">:</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">getAge</span><span class="p">()</span>
<span class="w">        </span><span class="k">default</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;no contract method&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">    </span><span class="p">}</span>
</code></pre></div>
<p>完整的合约代码如下：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span>
<span class="w">    </span><span class="s">&quot;strconv&quot;</span>

<span class="w">    </span><span class="s">&quot;chainmaker/pb/protogo&quot;</span>
<span class="w">    </span><span class="s">&quot;chainmaker/sandbox&quot;</span>
<span class="w">    </span><span class="s">&quot;chainmaker/sdk&quot;</span>
<span class="p">)</span>

<span class="c1">// AgeContract save and get age</span>
<span class="kd">type</span><span class="w"> </span><span class="nx">AgeContract</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
<span class="p">}</span>

<span class="c1">// InitContract 合约初始化方法，会在合约部署到链上时执行</span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InitContract</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Init contract success&quot;</span><span class="p">))</span>
<span class="p">}</span>

<span class="c1">// InvokeContract 调用合约，在链上执行合约时，实际调用的是这个方法</span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InvokeContract</span><span class="p">(</span><span class="nx">method</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>

<span class="w">    </span><span class="k">switch</span><span class="w"> </span><span class="nx">method</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;saveAge&quot;</span><span class="p">:</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">saveAge</span><span class="p">()</span>
<span class="w">    </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;getAge&quot;</span><span class="p">:</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">getAge</span><span class="p">()</span>
<span class="w">    </span><span class="k">default</span><span class="p">:</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;no contract method&quot;</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="p">}</span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">UpgradeContract</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Upgrade contract success&quot;</span><span class="p">))</span>
<span class="p">}</span>

<span class="c1">// saveAge 保存用户年龄信息</span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">saveAge</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="c1">//获取所有的合约参数</span>
<span class="w">    </span><span class="nx">args</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetArgs</span><span class="p">()</span>

<span class="w">    </span><span class="nx">name</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">])</span>
<span class="w">    </span><span class="nx">ageStr</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="s">&quot;age&quot;</span><span class="p">])</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nx">ageStr</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;name or age is empty&quot;</span>
<span class="w">        </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">        </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">strconv</span><span class="p">.</span><span class="nx">Atoi</span><span class="p">(</span><span class="nx">ageStr</span><span class="p">)</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;convert age to int fail. err: &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">()</span>
<span class="w">        </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">        </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">//保存用户年龄信息到链</span>
<span class="w">    </span><span class="nx">err</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">PutStateFromKey</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span><span class="w"> </span><span class="nx">ageStr</span><span class="p">)</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;put state from key fail. err: &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">()</span>
<span class="w">        </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">        </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">//返回合约执行成功信息</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;success&quot;</span><span class="p">))</span>
<span class="p">}</span>

<span class="c1">// getAge 获取用户年龄信息</span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">getAge</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="c1">//获取所有的合约参数</span>
<span class="w">    </span><span class="nx">args</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetArgs</span><span class="p">()</span>

<span class="w">    </span><span class="nx">name</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">])</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;name is  empty&quot;</span>
<span class="w">        </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">        </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;-1&quot;</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="nx">ageStr</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetStateFromKey</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;get state from key fail. err: &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">()</span>
<span class="w">        </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">        </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;-1&quot;</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">ageStr</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;age not found&quot;</span>
<span class="w">        </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">        </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;-1&quot;</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">//返回用户年龄</span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="nx">ageStr</span><span class="p">))</span>
<span class="p">}</span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="c1">//运行合约</span>
<span class="w">    </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sandbox</span><span class="p">.</span><span class="nx">Start</span><span class="p">(</span><span class="nb">new</span><span class="p">(</span><span class="nx">AgeContract</span><span class="p">))</span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nb">panic</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
</li>
<li>
<p>测试合约执行效果。至此我们的合约已经编写完成，下面我们可以通过合约调试功能测试一下合约执行效果。先双击 <code>main.go</code>，然后点击合约调试图标。如图所示，选中 <code>saveAge</code> 方法，增加 <code>name</code> 和 <code>age</code> 参数。然后点击构建合约，等构建完成之后点击执行合约，保存用户年龄信息到链上。</p>
<p>左侧 <strong>构建和执行合约</strong> 按钮下面会显示合约执行结果。</p>
<p><strong>控制台-&gt;输出</strong> 会打印合约执行日志 <code>sdk.Instance.Infof</code> 的内容。</p>
<p><strong>控制台-&gt;世界状态</strong> 会显示合约的世界状态。<code>{key:"Bob","value":"22"}</code></p>
<p><img alt="" src="../images/docs/invoke_saveAge.png" /></p>
</li>
<li>
<p>调用 <code>getAge</code> 方法，查询存储的用户年龄信息。如下图：选中 <code>getAge</code> 方法，增加 <code>name</code> 参数，然后点击构建并执行。</p>
<p>左侧 <strong>构建和执行合约</strong> 按钮下面会显示合约执行结果。</p>
<p><strong>控制台-&gt;输出</strong> 会打印合约执行日志 <code>sdk.Instance.Infof</code> 的内容。</p>
<p><strong>控制台-&gt;世界状态</strong> 会显示合约的世界状态。<code>{key:"Bob","value":"22"}</code></p>
<p><img alt="" src="../images/docs/invoke_getAge.png" /></p>
</li>
</ol>
<h3 id="sdk_2">SDK 详细介绍<a class="headerlink" href="#sdk_2" title="Permanent link">#</a></h3>
<p>上面我们一步一步创建了一个简单的合约，用到了SDK提供的一小部分方法。</p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="c1">//保存用户年龄信息到链上</span>
<span class="w">    </span><span class="nx">err</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">PutStateFromKey</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span><span class="w"> </span><span class="nx">ageStr</span><span class="p">)</span>
<span class="w">    </span><span class="c1">//从链上查询用户年龄信息</span>
<span class="w">    </span><span class="nx">ageStr</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetStateFromKey</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span>
</code></pre></div>
<p>下面详细介绍一下SDK提供的方法。</p>
<h4 id="sdkinterface"><code>SDKInterface</code> 接口<a class="headerlink" href="#sdkinterface" title="Permanent link">#</a></h4>
<p><code>SDKInterface</code> 定义了和链交互的方法，我们通过在合约中调用该接口的方法和链交互。方法列表如下：</p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="kd">type</span><span class="w"> </span><span class="nx">SDKInterface</span><span class="w"> </span><span class="kd">interface</span><span class="p">{</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取合约执行的参数</span>
<span class="w">        </span><span class="nx">GetArgs</span><span class="p">()</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">][]</span><span class="kt">byte</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">从链上查询信息</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">查询信息</span><span class="w"> </span><span class="nx">指定</span><span class="w"> </span><span class="nx">key</span><span class="w"> </span><span class="nx">field</span>
<span class="w">        </span><span class="nx">GetState</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span><span class="w"> </span><span class="nx">field</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="nx">GetStateWithExists</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span><span class="w"> </span><span class="nx">field</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">bool</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="nx">GetStateByte</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span><span class="w"> </span><span class="nx">field</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="nx">GetBatchState</span><span class="p">(</span><span class="nx">batchKeys</span><span class="w"> </span><span class="p">[]</span><span class="o">*</span><span class="nx">vmPb</span><span class="p">.</span><span class="nx">BatchKey</span><span class="p">)</span><span class="w"> </span><span class="p">([]</span><span class="o">*</span><span class="nx">vmPb</span><span class="p">.</span><span class="nx">BatchKey</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">查询信息</span><span class="w"> </span><span class="nx">指定</span><span class="w"> </span><span class="nx">key</span>
<span class="w">        </span><span class="nx">GetStateFromKey</span><span class="p">(</span><span class="nx">key</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="nx">GetStateFromKeyWithExists</span><span class="p">(</span><span class="nx">key</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">bool</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="nx">GetStateFromKeyByte</span><span class="p">(</span><span class="nx">key</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">存储数据到链上</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">存储信息</span><span class="w"> </span><span class="nx">指定key</span><span class="w"> </span><span class="nx">field</span>
<span class="w">        </span><span class="nx">PutState</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span><span class="w"> </span><span class="nx">field</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">value</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span>
<span class="w">        </span><span class="nx">PutStateByte</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span><span class="w"> </span><span class="nx">field</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">value</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">存储信息</span><span class="w"> </span><span class="nx">指定</span><span class="w"> </span><span class="nx">key</span>
<span class="w">        </span><span class="nx">PutStateFromKey</span><span class="p">(</span><span class="nx">key</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">value</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span>
<span class="w">        </span><span class="nx">PutStateFromKeyByte</span><span class="p">(</span><span class="nx">key</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">value</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">从链上删除数据</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">删除信息</span><span class="w"> </span><span class="nx">指定key</span><span class="w"> </span><span class="nx">field</span>
<span class="w">        </span><span class="nx">DelState</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span><span class="w"> </span><span class="nx">field</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">删除信息</span><span class="w"> </span><span class="nx">指定key</span>
<span class="w">        </span><span class="nx">DelStateFromKey</span><span class="p">(</span><span class="nx">key</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取合约创建者的组织ID</span>
<span class="w">        </span><span class="nx">GetCreatorOrgId</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取合约创建者的角色</span>
<span class="w">        </span><span class="nx">GetCreatorRole</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取合约创建者的公钥</span>
<span class="w">        </span><span class="nx">GetCreatorPk</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取交易发起者的组织ID</span>
<span class="w">        </span><span class="nx">GetSenderOrgId</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取交易交易发起者的角色</span>
<span class="w">        </span><span class="nx">GetSenderRole</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取交易发起者的公钥</span>
<span class="w">        </span><span class="nx">GetSenderPk</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取当前块高度</span>
<span class="w">        </span><span class="nx">GetBlockHeight</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取交易ID</span>
<span class="w">        </span><span class="nx">GetTxId</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取交易信息</span><span class="w"> </span>
<span class="w">        </span><span class="nx">GetTxInfo</span><span class="p">(</span><span class="nx">txId</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">获取交易时间戳</span>
<span class="w">        </span><span class="nx">GetTxTimeStamp</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">发布合约事件</span>
<span class="w">        </span><span class="nx">EmitEvent</span><span class="p">(</span><span class="nx">topic</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">data</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">)</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">记录合约日志</span>
<span class="w">        </span><span class="nx">Log</span><span class="p">(</span><span class="nx">message</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span>
<span class="w">        </span><span class="nx">Debugf</span><span class="p">(</span><span class="nx">format</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="o">...</span><span class="kd">interface</span><span class="p">{})</span>
<span class="w">        </span><span class="nx">Infof</span><span class="p">(</span><span class="nx">format</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="o">...</span><span class="kd">interface</span><span class="p">{})</span>
<span class="w">        </span><span class="nx">Warnf</span><span class="p">(</span><span class="nx">format</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="o">...</span><span class="kd">interface</span><span class="p">{})</span>
<span class="w">        </span><span class="nx">Errorf</span><span class="p">(</span><span class="nx">format</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="o">...</span><span class="kd">interface</span><span class="p">{})</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">跨合约调用</span>
<span class="w">        </span><span class="nx">CallContract</span><span class="p">(</span><span class="nx">contractName</span><span class="p">,</span><span class="w"> </span><span class="nx">method</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">args</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">][]</span><span class="kt">byte</span><span class="p">)</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">范围查询迭代器</span><span class="w"> </span><span class="p">[</span><span class="nx">startKey</span><span class="p">,</span><span class="w"> </span><span class="nx">limitKey</span><span class="p">)</span>
<span class="w">        </span><span class="nx">NewIterator</span><span class="p">(</span><span class="nx">startKey</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">limitKey</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">ResultSetKV</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">范围查询迭代器</span><span class="w"> </span><span class="p">[</span><span class="nx">key</span><span class="o">+</span><span class="nx">startField</span><span class="p">,</span><span class="w"> </span><span class="nx">key</span><span class="o">+</span><span class="nx">limitField</span><span class="p">)</span>
<span class="w">        </span><span class="nx">NewIteratorWithField</span><span class="p">(</span><span class="nx">key</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">startField</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">limitField</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">ResultSetKV</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">前缀范围查询迭代器</span><span class="w"> </span><span class="nx">有</span><span class="w"> </span><span class="s">`key+field`</span><span class="w"> </span><span class="nx">前缀的数据</span>
<span class="w">        </span><span class="nx">NewIteratorPrefixWithKeyField</span><span class="p">(</span><span class="nx">key</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">field</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">ResultSetKV</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">前缀范围查询迭代器</span><span class="w"> </span><span class="nx">有</span><span class="w"> </span><span class="s">`key`</span><span class="w"> </span><span class="nx">前缀的数据</span>
<span class="w">        </span><span class="nx">NewIteratorPrefixWithKey</span><span class="p">(</span><span class="nx">key</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">ResultSetKV</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">历史数据查询迭代器</span><span class="w"> </span><span class="nx">key</span><span class="o">+</span><span class="nx">field</span><span class="w"> </span><span class="nx">数据的历史版本</span>
<span class="w">        </span><span class="nx">NewHistoryKvIterForKey</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span><span class="w"> </span><span class="nx">field</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">KeyHistoryKvIter</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">查询交易发起方地址</span>
<span class="w">        </span><span class="nx">GetSenderAddr</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="nx">Sender</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>

<span class="w">        </span><span class="err">#</span><span class="w"> </span><span class="nx">查询原始调用方地址</span>
<span class="w">        </span><span class="nx">Origin</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="kt">error</span><span class="p">)</span><span class="w">  </span>
<span class="w">    </span><span class="p">}</span><span class="w">        </span>
<span class="w">    </span><span class="c1">// 结果集</span>
<span class="w">    </span><span class="kd">type</span><span class="w"> </span><span class="nx">ResultSet</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="c1">// NextRow get next row,</span>
<span class="w">        </span><span class="c1">// sql: column name is EasyCodec key, value is EasyCodec string val. as: val := ec.getString(&quot;columnName&quot;)</span>
<span class="w">        </span><span class="c1">// kv iterator: key/value is EasyCodec key for &quot;key&quot;/&quot;value&quot;, value type is []byte. as: k, _ := ec.GetString(&quot;key&quot;) v, _ := ec.GetBytes(&quot;value&quot;)</span>
<span class="w">        </span><span class="nx">NextRow</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="nx">serialize</span><span class="p">.</span><span class="nx">EasyCodec</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">        </span><span class="c1">// HasNext return does the next line exist</span>
<span class="w">        </span><span class="nx">HasNext</span><span class="p">()</span><span class="w"> </span><span class="kt">bool</span>
<span class="w">        </span><span class="c1">// Close .</span>
<span class="w">        </span><span class="nx">Close</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">bool</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="kd">type</span><span class="w"> </span><span class="nx">ResultSetKV</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">ResultSet</span>
<span class="w">        </span><span class="c1">// Next return key,field,value,code</span>
<span class="w">        </span><span class="nx">Next</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="kd">type</span><span class="w"> </span><span class="nx">KeyHistoryKvIter</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">ResultSet</span>
<span class="w">        </span><span class="c1">// Next return txId, blockHeight, timestamp, value, isDelete, error</span>
<span class="w">        </span><span class="nx">Next</span><span class="p">()</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="nx">KeyModification</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span>
<span class="w">    </span><span class="p">}</span>
</code></pre></div>
<p>写合约的时候我们通过编写代码完成合约逻辑，SDK提供了合约和链交互的方法，帮助我们完成和链交互。</p>
<h4 id="sdkinterface_1"><code>SDKInterface</code> 详细介绍<a class="headerlink" href="#sdkinterface_1" title="Permanent link">#</a></h4>
<ol>
<li>
<p>跨合约调用，即在A合约中调用B合约的方法。跨合约调用需要用到 <code>CallContract</code> 方法。代码如下：</p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="c1">//crossCall 跨合约调用</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">crossCall</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>

<span class="w">        </span><span class="c1">//要调用的合约的基本信息</span>
<span class="w">        </span><span class="nx">contractName</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;age_contract&quot;</span>
<span class="w">        </span><span class="nx">calledMethod</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;getAge&quot;</span>

<span class="w">        </span><span class="c1">//跨合约调用的参数</span>
<span class="w">        </span><span class="nx">crossContractArgs</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">][]</span><span class="kt">byte</span><span class="p">)</span>
<span class="w">        </span><span class="nx">crossContractArgs</span><span class="p">[</span><span class="s">&quot;method&quot;</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="nx">calledMethod</span><span class="p">)</span>
<span class="w">        </span><span class="nx">crossContractArgs</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Bob&quot;</span><span class="p">)</span>

<span class="w">        </span><span class="c1">//开合约调用响应信息</span>
<span class="w">        </span><span class="nx">response</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">CallContract</span><span class="p">(</span><span class="nx">contractName</span><span class="p">,</span><span class="w"> </span><span class="nx">calledMethod</span><span class="p">,</span><span class="w"> </span><span class="nx">crossContractArgs</span><span class="p">)</span>
<span class="w">        </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">EmitEvent</span><span class="p">(</span><span class="s">&quot;cross contract&quot;</span><span class="p">,</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&quot;success&quot;</span><span class="p">})</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">response</span>
<span class="w">    </span><span class="p">}</span>
</code></pre></div>
</li>
<li>
<p>迭代器使用，查询用户年龄的历史版本。</p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="c1">//historyKvIterator 历史迭代器</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">historyKvIterator</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">key</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;Bob&quot;</span>
<span class="w">        </span><span class="c1">//创建历史迭代器</span>
<span class="w">        </span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">NewHistoryKvIterForKey</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">msg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;failed to call get_state&quot;</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Log</span><span class="p">(</span><span class="nx">msg</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&quot; &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">())</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">msg</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="c1">//判断迭代器是否有数据，如果有迭代输出数据</span>
<span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">HasNext</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">v</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Next</span><span class="p">()</span>
<span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">                </span><span class="nx">msg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;failed to call iterator&quot;</span>
<span class="w">                </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Log</span><span class="p">(</span><span class="nx">msg</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&quot; &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">())</span>
<span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">msg</span><span class="p">)</span>
<span class="w">            </span><span class="p">}</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Log</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Sprintf</span><span class="p">(</span><span class="s">&quot;NewHistoryKvIterForKey %v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="p">))</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>
</code></pre></div>
</li>
<li>
<p>完整合约。包含 保存用户年龄信息<code>saveAge</code>、 查询用户年龄信息<code>getAge</code> 开合约调用<code>crossCall</code> 和 历史迭代器<code>historyKvIterator</code>。</p>
</li>
</ol>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="kn">package</span><span class="w"> </span><span class="nx">main</span>

<span class="w">    </span><span class="kn">import</span><span class="w"> </span><span class="p">(</span>
<span class="w">        </span><span class="s">&quot;strconv&quot;</span>

<span class="w">        </span><span class="s">&quot;chainmaker/pb/protogo&quot;</span>
<span class="w">        </span><span class="s">&quot;chainmaker/sandbox&quot;</span>
<span class="w">        </span><span class="s">&quot;chainmaker/sdk&quot;</span>
<span class="w">        </span><span class="s">&quot;fmt&quot;</span>
<span class="w">    </span><span class="p">)</span>

<span class="w">    </span><span class="c1">// AgeContract save and get age</span>
<span class="w">    </span><span class="kd">type</span><span class="w"> </span><span class="nx">AgeContract</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// InitContract 合约初始化方法，会在合约部署到链上时执行</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InitContract</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Init contract success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// InvokeContract 调用合约，在链上执行合约时，实际调用的是这个方法</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InvokeContract</span><span class="p">(</span><span class="nx">method</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>

<span class="w">        </span><span class="k">switch</span><span class="w"> </span><span class="nx">method</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;saveAge&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">saveAge</span><span class="p">()</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;getAge&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">getAge</span><span class="p">()</span>

<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;crossCall&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">crossCall</span><span class="p">()</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;historyKvIterator&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">historyKvIterator</span><span class="p">()</span>
<span class="w">        </span><span class="k">default</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;no contract method&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">    </span><span class="p">}</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">UpgradeContract</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Upgrade contract success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// saveAge 保存用户年龄信息</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">saveAge</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="c1">//获取所有的合约参数</span>
<span class="w">        </span><span class="nx">args</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetArgs</span><span class="p">()</span>

<span class="w">        </span><span class="nx">name</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">])</span>
<span class="w">        </span><span class="nx">ageStr</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="s">&quot;age&quot;</span><span class="p">])</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nx">ageStr</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;name or age is empty&quot;</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">strconv</span><span class="p">.</span><span class="nx">Atoi</span><span class="p">(</span><span class="nx">ageStr</span><span class="p">)</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;convert age to int fail. err: &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">()</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="c1">//保存用户年龄信息到链</span>
<span class="w">        </span><span class="nx">err</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">PutStateFromKey</span><span class="p">(</span><span class="nx">name</span><span class="p">,</span><span class="w"> </span><span class="nx">ageStr</span><span class="p">)</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;put state from key fail. err: &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">()</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="c1">//返回合约执行成功信息</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">// getAge 获取用户年龄信息</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">getAge</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="c1">//获取所有的合约参数</span>
<span class="w">        </span><span class="nx">args</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetArgs</span><span class="p">()</span>

<span class="w">        </span><span class="nx">name</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">args</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">])</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;name is  empty&quot;</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;-1&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="nx">ageStr</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">GetStateFromKey</span><span class="p">(</span><span class="nx">name</span><span class="p">)</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;get state from key fail. err: &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">()</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;-1&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">ageStr</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">message</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;age not found&quot;</span>
<span class="w">            </span><span class="c1">//打印日志，调试合约时，日志会在控制台输出中展示</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Infof</span><span class="p">(</span><span class="nx">message</span><span class="p">)</span>
<span class="w">            </span><span class="c1">//返回合约执行错误信息</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;-1&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="c1">//返回用户年龄</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="nx">ageStr</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">crossCall</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>

<span class="w">        </span><span class="c1">//要调用的合约的基本信息</span>
<span class="w">        </span><span class="nx">contractName</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;age_contract&quot;</span>
<span class="w">        </span><span class="nx">calledMethod</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;getAge&quot;</span>

<span class="w">        </span><span class="c1">//跨合约调用的参数</span>
<span class="w">        </span><span class="nx">crossContractArgs</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">][]</span><span class="kt">byte</span><span class="p">)</span>
<span class="w">        </span><span class="nx">crossContractArgs</span><span class="p">[</span><span class="s">&quot;method&quot;</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="nx">calledMethod</span><span class="p">)</span>
<span class="w">        </span><span class="nx">crossContractArgs</span><span class="p">[</span><span class="s">&quot;name&quot;</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;Bob&quot;</span><span class="p">)</span>

<span class="w">        </span><span class="c1">//开合约调用响应信息</span>
<span class="w">        </span><span class="nx">response</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">CallContract</span><span class="p">(</span><span class="nx">contractName</span><span class="p">,</span><span class="w"> </span><span class="nx">calledMethod</span><span class="p">,</span><span class="w"> </span><span class="nx">crossContractArgs</span><span class="p">)</span>
<span class="w">        </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">EmitEvent</span><span class="p">(</span><span class="s">&quot;cross contract&quot;</span><span class="p">,</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&quot;success&quot;</span><span class="p">})</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">response</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="c1">//historyKvIterator 历史迭代器</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">historyKvIterator</span><span class="p">()</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="nx">key</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;Bob&quot;</span>
<span class="w">        </span><span class="c1">//创建历史迭代器</span>
<span class="w">        </span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">NewHistoryKvIterForKey</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">msg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;failed to call get_state&quot;</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Log</span><span class="p">(</span><span class="nx">msg</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&quot; &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">())</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">msg</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="c1">//判断迭代器是否有数据，如果有迭代输出数据</span>
<span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">HasNext</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nx">v</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Next</span><span class="p">()</span>
<span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">                </span><span class="nx">msg</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;failed to call iterator&quot;</span>
<span class="w">                </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Log</span><span class="p">(</span><span class="nx">msg</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&quot; &quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">Error</span><span class="p">())</span>
<span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="nx">msg</span><span class="p">)</span>
<span class="w">            </span><span class="p">}</span>
<span class="w">            </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Instance</span><span class="p">.</span><span class="nx">Log</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Sprintf</span><span class="p">(</span><span class="s">&quot;NewHistoryKvIterForKey %v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="p">))</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Success</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&quot;success&quot;</span><span class="p">))</span>
<span class="w">    </span><span class="p">}</span>

<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="c1">//运行合约</span>
<span class="w">        </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sandbox</span><span class="p">.</span><span class="nx">Start</span><span class="p">(</span><span class="nb">new</span><span class="p">(</span><span class="nx">AgeContract</span><span class="p">))</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nb">panic</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">    </span><span class="p">}</span>
</code></pre></div>
<h3 id="_1">编写合约注意事项<a class="headerlink" href="#_1" title="Permanent link">#</a></h3>
<ol>
<li>
<p>合约工程目录下必须有一个 <code>main.go</code>，且 <code>main.go</code> 的包名需要是 <code>main</code>，合约的入口需要在 <code>main.go</code> 中，且 <code>InvokeContract()</code> 方法代码需要在 <code>main.go</code> 中。即 ：</p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="kn">package</span><span class="w"> </span><span class="nx">main</span>

<span class="w">    </span><span class="kn">import</span><span class="w"> </span><span class="p">(</span>

<span class="w">    </span><span class="s">&quot;chainmaker/pb/protogo&quot;</span>
<span class="w">    </span><span class="s">&quot;chainmaker/sandbox&quot;</span>
<span class="w">    </span><span class="s">&quot;chainmaker/sdk&quot;</span>
<span class="w">    </span><span class="p">)</span>

<span class="w">    </span><span class="o">...</span><span class="w"> </span><span class="o">...</span>
<span class="w">    </span><span class="o">...</span><span class="w"> </span><span class="o">...</span>


<span class="w">    </span><span class="c1">// InvokeContract 调用合约，在链上执行合约时，实际调用的是这个方法</span>
<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">ac</span><span class="w"> </span><span class="o">*</span><span class="nx">AgeContract</span><span class="p">)</span><span class="w"> </span><span class="nx">InvokeContract</span><span class="p">(</span><span class="nx">method</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="nx">protogo</span><span class="p">.</span><span class="nx">Response</span><span class="w"> </span><span class="p">{</span>

<span class="w">        </span><span class="k">switch</span><span class="w"> </span><span class="nx">method</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;saveAge&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">saveAge</span><span class="p">()</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;getAge&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">getAge</span><span class="p">()</span>

<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;crossCall&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">crossCall</span><span class="p">()</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;historyKvIterator&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">ac</span><span class="p">.</span><span class="nx">historyKvIterator</span><span class="p">()</span>
<span class="w">        </span><span class="k">default</span><span class="p">:</span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;no contract method&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>

<span class="w">    </span><span class="p">}</span>

<span class="w">        </span><span class="c1">// 合约入口</span>

<span class="w">    </span><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="c1">//运行合约</span>
<span class="w">        </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">sandbox</span><span class="p">.</span><span class="nx">Start</span><span class="p">(</span><span class="nb">new</span><span class="p">(</span><span class="nx">AgeContract</span><span class="p">))</span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span>
<span class="w">            </span><span class="nb">panic</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>
<span class="w">    </span><span class="p">}</span>
</code></pre></div>
</li>
<li>
<p><code>InvokeContract</code> 里面关联方法逻辑需要是如下模式（合约调试会根据下面的模式解析方法名）。注意不要在 case 后面使用定义的常量。  </p>
<div class="highlight"><pre><span></span><code><span class="w">    </span><span class="k">switch</span><span class="w"> </span><span class="nx">method</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;字符串&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="o">...</span><span class="w"> </span><span class="o">...</span>
<span class="w">        </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;字符串&quot;</span><span class="p">:</span>
<span class="w">            </span><span class="o">...</span><span class="w"> </span><span class="o">...</span>
<span class="w">        </span><span class="k">default</span><span class="p">:</span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">sdk</span><span class="p">.</span><span class="nx">Error</span><span class="p">(</span><span class="s">&quot;no contract method&quot;</span><span class="p">)</span>
<span class="w">        </span><span class="p">}</span>
</code></pre></div>
</li>
<li>
<p>合约必须包含<code>InitContract()</code> 方法和 <code>UpgradeContract()</code>方法,合约部署到链上以后才可以进行安装和升级。     </p>
</li>
<li>
<p>不能使用全局变量。在编写合约时，不要使用全局变量来存储数据，数据的存储可以直接存到链上，用 <code>getState</code> 和 <code>putState</code> 等方法存储。</p>
</li>
<li>
<p>不支持在合约工程内创建内嵌的 go module。</p>
</li>
</ol>





                
              </article>
            </div>
          
          
        </div>
        
      </main>
      
        <footer class="md-footer">
  
  <div class="md-footer-meta md-typeset">
    <div class="md-footer-meta__inner md-grid">
      <div class="md-copyright">
  
  
    Made with
    <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
      Material for MkDocs
    </a>
  
</div>
      
    </div>
  </div>
</footer>
      
    </div>
    <div class="md-dialog" data-md-component="dialog">
      <div class="md-dialog__inner md-typeset"></div>
    </div>
    
    <script id="__config" type="application/json">{"base": "..", "features": [], "search": "../assets/javascripts/workers/search.74e28a9f.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
    
    
      <script src="../assets/javascripts/bundle.220ee61c.min.js"></script>
      
    
  </body>
</html>